using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Yoozoo.Gameplay.Liberty
{
    [RequireComponent(typeof(LineRenderer))]
   public class Parabola : MonoBehaviour
   {
       /// <summary>
       /// 根据 起始、结束点 和 最大高度 给刚体施力
       /// </summary>
       /// <param name="rigidbody">被施力的刚体</param>
       /// <param name="startPoint">起始点</param>
       /// <param name="endPoint">结束点</param>
       /// <param name="maxHeight">最大高度</param>
       public static void AddRigidbodyForce(Rigidbody rigidbody, Vector3 startPoint, Vector3 endPoint, float maxHeight)
       {
           // 获取完刚体现有速度信息，才能给刚体加力
           Vector3 force = ParabolaUtils.CalculateParabolaForce(rigidbody.mass, startPoint, endPoint, maxHeight);
           rigidbody.AddForce(force);
       }
       
       private LineRenderer _LineRenderer;

       [SerializeField]
       private string _AssetPath;
       public string AssetPath { get; set; }
       // 物理预测信息
       // 物理碰撞LayerMask
       [SerializeField]
       private LayerMask _LayerMask;
       // 每次预测的步长 (几次FixedUpdate)
       [SerializeField] 
       private int _PredictStep = 2;
       // 初始预测数量
       [SerializeField]
       private int _PredictCount = 5;
       // 后续每次预测数量 (直到达到最大值 或者 碰撞到物体)
       [SerializeField]
       private int _AddPredictCount = 5;
       // 最大预测数量
       [SerializeField]
       private int _MaxPredictCount = 200;
       // 物理预测数据记录
       private List<Vector3[]> _PredictDatas = new List<Vector3[]>();
       
       RaycastHit _HitInfo;
   
       // 绘制采样点
       private List<Vector3> _Points = new List<Vector3>();
       
       void Awake()
       {
           this._LineRenderer = this.GetComponent<LineRenderer>();
       }

       void LateUpdate()
       {
           if (_Points.Count > 0)
           {
               _LineRenderer.positionCount = _Points.Count;
               _LineRenderer.SetPositions(_Points.ToArray());
           }
           else
           {
               _LineRenderer.positionCount = 0;
           }
       }

       /// <summary>
       /// 根据 起始、结束点 和 最大高度 预测刚体抛物线轨迹
       /// </summary>
       /// <param name="mass">刚体质量</param>
       /// <param name="mass">刚体阻力</param>
       /// <param name="startPoint">起始点</param>
       /// <param name="endPoint">结束点</param>
       /// <param name="maxHeight">最大高度</param>
       public void PredictParabola(float mass, float drag, Vector3 startPoint, Vector3 endPoint, float maxHeight)
       {
           // 计算刚体现有速度
           Vector3 velocity = Vector3.zero;
           // 计算刚体重力
           Vector3 gravity = UnityEngine.Physics.gravity;
           // 碰撞检测两点的index
           int colStartIndex = 0; 
           int colEndIdx = 0;
           // 
           Vector3 point1, point2;
           Vector3 vector;
           
           // 获取完刚体现有速度信息，才能给刚体加力
           Vector3 force = ParabolaUtils.CalculateParabolaForce(mass, startPoint, endPoint, maxHeight);
   
           // 开始预测抛物线
           _PredictDatas.Clear();
           ParabolaUtils.CalculateMovements(_PredictDatas, startPoint, velocity, gravity, _PredictCount, _PredictStep, force, mass, drag);
   
           // 持续预测直到发生碰撞或达到预测最大数量
           while (_PredictDatas.Count<_MaxPredictCount)
           {
               // 找出最新预测的起始点和结束点，做碰撞检测
               colStartIndex = colEndIdx;
               colEndIdx = _PredictDatas.Count-1;
               point1 = _PredictDatas[colStartIndex][0];   // start
               point2 = _PredictDatas[colEndIdx][0];   // end
               vector = point2 - point1;
   
               // 预测抛物线碰撞到物体
               if (UnityEngine.Physics.Raycast(point1, vector.normalized, out _HitInfo, vector.magnitude, _LayerMask))
               {
                   break;
               }
               
               // 没有碰撞到物体，继续预测
               Vector3[] lastPredictData = _PredictDatas[_PredictDatas.Count - 1]; // 0: position 1: velocity
               ParabolaUtils.CalculateMovements(_PredictDatas, lastPredictData[0], lastPredictData[1], gravity, _AddPredictCount, _PredictStep, Vector3.zero, mass, drag);
           }
   
           // 划线数据
           _Points.Clear();
           _Points.Add(startPoint);
           for (int i = 0; i < _PredictDatas.Count; ++i)
           {
               _Points.Add(_PredictDatas[i][0]);
           }
       }

       /// <summary>
       /// 清空绘制采样点
       /// </summary>
       public void ClearPoints()
       {
           _Points.Clear();
           _LineRenderer.positionCount = 0;
       }

       public void SetPoints(Vector3[] points)
       {
           _Points.Clear();
           _Points.AddRange(points);
       }
       
   } 
}
